<template>
  <g 
    :id="`node-${node.id}`"
    :class="['workflow-node', { selected: props.selected, dragging: isDragging }]"
    :transform="`translate(${props.node.position.x + 2},${props.node.position.y + 2})`"
    @click.stop="handleClick"
  >
    <!-- 背景 -->
    <rect
      class="node-background"
      x="-2"
      y="-2"
      :width="nodeWidth "
      :height="getNodeHeight()"
      rx="4"
      fill="rgba(0, 0, 0, 0.6)"
      :stroke="props.selected ? '#409EFF' : 'transparent'"
      stroke-width="2"
	  @mousedown="handleDragStart"
	  :style="{ cursor: headCursor }"
    />
	
    <!-- 头部 -->
	
    <g 
      class="node-head"
      :id="`${node.id}_head`"
      @mousedown="handleDragStart"
      :style="{ cursor: headCursor }"
	  v-if="props.node.showHead=='1'"
    >
      <!-- 头部背景渐变 -->
      <defs>
        <linearGradient :id="`headerGradient-${node.id}`" x1="0%" y1="0%" x2="0%" y2="100%">
          <!-- 顶部亮色 -->
          <stop offset="0%" :stop-color="props.node.color" stop-opacity="0.5" />
          <!-- 中间主色 -->
          <stop offset="40%" :stop-color="props.node.color" stop-opacity="0.2" />
          <!-- 底部暗色 -->
          <stop offset="100%" :stop-color="props.node.color" stop-opacity="0.5" />
        </linearGradient>

        <!-- 发光效果 -->
        <filter :id="`glow-${node.id}`">
          <feGaussianBlur stdDeviation="0.8" result="coloredBlur"/>
          <feMerge>
            <feMergeNode in="coloredBlur"/>
            <feMergeNode in="SourceGraphic"/>
          </feMerge>
        </filter>
      </defs>
      
      <!-- 头部背景路径 -->
      <path
        :d="`M0,4 A4,4 0 0,1 4,0 H${nodeWidth  - 8} A4,4 0 0,1 ${nodeWidth  - 4},4 V30 H0 Z`"
        :fill="`url(#headerGradient-${node.id})`"
        :filter="`url(#glow-${node.id})`"
        style="filter: brightness(1.2)"
      />
      
      <!-- 图标 -->
      <foreignObject 
        x="10"
        y="0" 
        width="20" 
        height="20"
        style="paint-order: stroke;"
      >
        <el-icon class="node-icon" size="16" style="color: white;" v-if="node.icon && node.icon.startsWith('el-icon')">
          <component :is="node.icon.replace('el-icon-', '')" />
        </el-icon> 
		<svg-icon v-else-if="node.icon" :icon-class="node.icon"  class="node-icon" size="16" style="color: white;"/>
      </foreignObject>
      
      <!-- 标题 -->
      <text
        x="34"
        y="14"
        text-anchor="start"
        dominant-baseline="middle"
        fill="#bbbbbb"
        font-size="13px"
        pointer-events="none"
        user-select="none"
        style="paint-order: stroke;"
        shape-rendering="geometricPrecision"
        text-rendering="geometricPrecision"
      >
        {{ node.title }}
      </text>
    </g>
	
    <!-- 内容 -->
    <g class="node-body" :id="`${node.id}_body`">
		
      <g 
        class="node-content-row"
        :transform="`translate(0, ${props.node.showHead=='1'?35:5})`"
      >
        <!-- 输入端口组容器 -->
        <g class="input-ports-container">
          <g 
            v-for="(input, index) in node.data.inputs" 
            :key="input.id"
            class="port-group input-port"
            :transform="`translate(0, ${index * 30})`"
          >
            <defs>
              <linearGradient :id="`portGradient-${node.id}-input-${input.id}`" x1="0%" y1="0%" x2="100%" y2="0%">
                <stop offset="0%" :stop-color="getParamColor(input?.type,input?.fieldType)" stop-opacity="0.1" />
                <stop offset="50%" :stop-color="getParamColor(input?.type,input?.fieldType)" stop-opacity="0.5" />
                <stop offset="100%" :stop-color="getParamColor(input?.type,input?.fieldType)" stop-opacity="0.1" />
              </linearGradient>
            </defs>
			
            <!-- 输入端口背景 -->
            <rect
              class="port-background"
              x="2"
              y="0"
              :width="getPortBackgroundWidth( (input.click=='1'? (input.value? (input.name +'('+ input.value+')'):(input.name)): input.name) )"
              height="20"
              rx="2"
              :fill="`url(#portGradient-${node.id}-input-${input.id})`"
			  :id='`input-${input.id}-port-bg`'
			  :portId="`input-${node.id}-${input.id}-port`"
			  @click.stop="handleContextMenu(`input-${node.id}-${input.id}-port`, $event, input)"
            />
            
            <!-- 输入端口三角形 -->
            <template v-if="(input?.type)=='exec'">
              <path
                class="node-input"
                d="M 7,4 L 17,10 L 7,16 L 7,4"
                :fill="isPortConnected(`input-${node.id}-${input.id}-port`) ? '#fff' : 'none'"
                stroke="#fff"
                stroke-width="1.2"
                shape-rendering="geometricPrecision"
                stroke-linejoin="round"
                stroke-linecap="round"
                :id='`input-${node.id}-${input.id}-port-sign`'
                :portId="`input-${node.id}-${input.id}-port`"
              /> 
            </template>
			
			
			<!-- array输入 -->
			<template v-else-if="(input?.type)=='array'">
			  <g 
			    :id='`input-${node.id}-${input.id}-port-sign`'
			    :portId="`input-${node.id}-${input.id}-port`"
			    :transform="`translate(10, 10)`"
			    @click.stop="handleContextMenu(`input-${node.id}-${input.id}-port`, $event, input)"
			  >
			    <!-- 连接时显示的中间方块 -->
			    <rect x="-0.75" y="-0.75" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" 
			      v-if="isPortConnected(`input-${node.id}-${input.id}-port`) || input.value" />
			      
			    <!-- 始终显示的 8 个方块 -->
			    <rect x="-4" y="-4" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			    <rect x="-0.75" y="-4" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			    <rect x="2.5" y="-4" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			    
			    <rect x="-4" y="-0.75" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			    <rect x="2.5" y="-0.75" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			    
			    <rect x="-4" y="2.5" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			    <rect x="-0.75" y="2.5" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			    <rect x="2.5" y="2.5" width="2.5" height="2.5" :fill="getParamColor(input?.type,input?.fieldType)" />
			  </g>
			  
			  <!-- 输入端口名称 -->
<!-- 			  <text
			    x="25"
			    y="14"
			    :id='`input-${node.id}-${input.id}-port-desc`'
			    class="port-label"
			    fill="#959595"
			    font-size="10px"
			    @click.stop="handlePortClick(`input-${node.id}-${input.id}-port`)"
			  >
			    {{ input.value || input.name }}
			  </text> -->
			</template>
			
			<template v-else>
				<circle 
					:id='`input-${node.id}-${input.id}-port-sign`' 
					:portId="`input-${node.id}-${input.id}-port`" 
					cx="10" 
					cy="10" 
					r="5" 
					:stroke="getParamColor(input?.type,input?.fieldType)" 
					stroke-width="2" 
					:fill="isPortConnected(`input-${node.id}-${input.id}-port`) || input.value ? getParamColor(input?.type,input?.fieldType) : 'none'"
					@click.stop="handleContextMenu(`input-${node.id}-${input.id}-port`, $event, input)"
				/>
			</template>
			
            <!-- 输入端口名称 -->
            <text
			  v-if="input.click=='1'"
			  :id='`input-${node.id}-${input.id}-port-desc`'
              x="25"
              y="14"
              class="port-label"
              fill="#fff"
              font-size="10px"
			  user-select="none"
			  pointer-events="painted"
			  @click.stop="handleContextMenu(`input-${node.id}-${input.id}-port`, $event, input)"
            >
              {{ input.value? (input.name +'('+ input.value+')'):(input.name)  }}
            </text>
			
			<text
			  v-else
			  :id='`input-${node.id}-${input.id}-port-desc`'
			  x="25"
			  y="14"
			  class="port-label"
			  fill="#fff"
			  font-size="10px"
			  user-select="none"
			  pointer-events="none"
			>
			  {{ input.name }}
			</text>
          </g>
        </g>
        
        <!-- 输出端口组容器 -->
        <g class="output-ports-container">
          <g 
            v-for="(output, index) in node.data.outputs" 
            :key="output.id"
            class="port-group output-port"
            :transform="`translate(0, ${index * 30})`"
          >
		  
            <defs>
              <linearGradient :id="`portGradient-${node.id}-output-${output.id}`" x1="0%" y1="0%" x2="100%" y2="0%">
                <stop offset="0%" :stop-color="getParamColor(output?.type,output?.fieldType)" stop-opacity="0.1" />
                <stop offset="50%" :stop-color="getParamColor(output?.type,output?.fieldType)" stop-opacity="0.5" />
                <stop offset="100%" :stop-color="getParamColor(output?.type,output?.fieldType)" stop-opacity="0.1" />
              </linearGradient>
            </defs>
			
            <!-- 输出端口背景 -->
            <rect
              :x="nodeWidth - getPortBackgroundWidth( (output.click=='1'? (output.value? (output.name +'('+ output.value+')'):(output.name)): output.name) ) - 5"
              y="0"
			  :width="getPortBackgroundWidth( (output.click=='1'? (output.value? (output.name +'('+ output.value+')'):(output.name)): output.name) )"
              height="20"
              rx="2"
              class="port-background"
              :fill="`url(#portGradient-${node.id}-output-${output.id})`"
              :portId="`output-${node.id}-${output.id}-port`"
			  @click.stop="handleContextMenu(`output-${node.id}-${output.id}-port`, $event, output)"
            />
			
			<!-- 执行输出 -->
            <template v-if="(output?.type)=='exec'">
              <path
                :id='`output-${node.id}-${output.id}-port-sign`'
                class="node-out"
                :d="`M ${nodeWidth - 21},4 L ${nodeWidth - 11},10 L ${nodeWidth - 21},16 L ${nodeWidth - 21},4`"
                :fill="isPortConnected(`output-${node.id}-${output.id}-port`) ? '#fff' : 'none'"
                stroke="#fff"
                stroke-width="1.2"
                shape-rendering="geometricPrecision"
                stroke-linejoin="round"
                stroke-linecap="round"
                :portId="`output-${node.id}-${output.id}-port`"
                @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)"
              />
				<g class="port-label-group">
				  <text
					:x="nodeWidth - 30"
					y="14"
					class="port-label"
					text-anchor="end"
					fill="#fff"
					font-size="10px"
					user-select="none"
					pointer-events="painted"
					@click.stop="handleContextMenu(`output-${node.id}-${output.id}-port`, $event, output)"
				  >
					{{ node?.type=='Sequence'  ? (output?.name + '&nbsp;' + index) : (output?.name)}}
				  </text>
				</g>
            </template>
			
			<!-- array输出 -->
            <template v-else-if="(output?.type)=='array'">
              <g 
                :id='`output-${node.id}-${output.id}-port-sign`'
                :portId="`output-${node.id}-${output.id}-port`"
                :transform="`translate(${nodeWidth - 16}, 10)`"
              >
                <!-- 连接时显示的中间方块 -->
                <rect x="-0.75" y="-0.75" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" 
                  v-if="isPortConnected(`output-${node.id}-${output.id}-port`)" />
                  
                <!-- 始终显示的 8 个方块 -->
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="-4" y="-4" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="-0.75" y="-4" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="2.5" y="-4" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
                
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="-4" y="-0.75" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="2.5" y="-0.75" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
                
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="-4" y="2.5" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="-0.75" y="2.5" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
                <rect @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)" x="2.5" y="2.5" width="2.5" height="2.5" :fill="getParamColor(output?.type,output?.fieldType)" />
              </g>
			  
			  <!-- 输出端口名称 -->
			  <text
			    :x="nodeWidth - 30"
			    y="14"
			    :id='`output-${node.id}-${output.id}-port-desc`'
			    class="port-label"
			    text-anchor="end"
			    fill="#f7f7f7"
			    font-size="10px"
				font-family='sans-serif'
				user-select="none"
				pointer-events="painted"
				@click.stop="handleContextMenu(`output-${node.id}-${output.id}-port`, $event, output)"
			  >
			    {{ output?.name }}
			  </text>
			  
            </template>
			
			<template v-else-if="(output?.type)=='reference'">
				<circle 
				  :id='`output-${node.id}-${output.id}-port-sign`' 
				  :portId="`output-${node.id}-${output.id}-port`"  
				  :cx="nodeWidth - 16" 
				  cy="10" 
				  r="5" 
				  :stroke="getParamColor(output?.type,output?.fieldType)" 
				  stroke-width="2" 
				  :fill="isPortConnected(`output-${node.id}-${output.id}-port`) ? getParamColor(output?.type,output?.fieldType) : 'none'"
				  @click.stop="addReference"
				/>
				<!-- 添加加号 -->
 				<g 
				  :transform="`translate(${nodeWidth - 16}, 10)`"
				  pointer-events="none"
				>
					<line 
						x1="-3" 
						y1="0" 
						x2="3" 
						y2="0" 
						stroke="#fff" 
						stroke-width="1.5"
					/>
					<line 
						x1="0" 
						y1="-3" 
						x2="0" 
						y2="3" 
						stroke="#fff" 
						stroke-width="1.5"
					/>
				</g>
				
				<!-- 输出端口名称 -->
				<text
				  :x="nodeWidth - 30"
				  y="14"
				  :id='`output-${node.id}-${output.id}-port-desc`'
				  class="port-label"
				  text-anchor="end"
				  fill="#fff"
				  font-size="10px"
				  user-select="none"
				  pointer-events="painted"
				  @click.stop="addReference"
				>
				  {{ output?.name }}
				</text>
			</template>
			
			<template v-else>
				<circle 
				  :id='`output-${node.id}-${output.id}-port-sign`' 
				  :portId="`output-${node.id}-${output.id}-port`"  
				  :cx="nodeWidth - 16" 
				  cy="10" 
				  r="5" 
				  :stroke="getParamColor(output?.type,output?.fieldType)" 
				  stroke-width="2" 
				  :fill="isPortConnected(`output-${node.id}-${output.id}-port`) ? getParamColor(output?.type,output?.fieldType) : 'none'"
				  @mousedown.stop="(e: MouseEvent) => handleDragPortStart(`output-${node.id}-${output.id}-port`, e)"
				  @click.stop="handleContextMenu(`output-${node.id}-${output.id}-port`, $event, output)"
				/>
				
				<!-- 输出端口名称 -->
				<text
				  :x="nodeWidth - 30"
				  y="14"
				  :id='`output-${node.id}-${output.id}-port-desc`'
				  class="port-label"
				  text-anchor="end"
				  fill="#fff"
				  font-size="10px"
				  user-select="none"
				  pointer-events="painted"
				  @click.stop="handleContextMenu(`output-${node.id}-${output.id}-port`, $event, output)"
				>
				  {{ output.value? (output.name +'('+ output.value+')'):(output.name)  }}
				</text>
			</template>
          </g>
        </g>
      </g>
    </g>    
    
  </g>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue';
import type { WorkflowNode, Port ,Connection } from '@/stores/workflow';
import type { Position } from '../types';
import { useWorkflowStore } from '@/stores/workflow';
import { v4 as uuidv4 } from 'uuid';
const props = defineProps<{
  node: WorkflowNode;
  selected?: boolean;
  svgContainer:SVGSVGElement;
}>();
const workflowStore = useWorkflowStore();
const isFirst=ref<boolean>(true);
const emit = defineEmits<{
  (e: 'select', nodeId: string): void;
  (e: 'update:position', nodeId: string, position: Position): void;
  (e: 'port:click', portId: string,port:Port ,node: WorkflowNode, canConnect?: (sourcePortId: string, targetPortId: string) => boolean): void;
  (e: 'port:edit', portId: string, node: WorkflowNode): void;
  (e: 'port:delete', portId: string, node: WorkflowNode): void;
  (e: 'port:menu:show', portId: string, node: WorkflowNode,port:Port,event: MouseEvent): void;
  (e: 'port:menu:hide'): void;
  (e: 'port:input', portId: string, node: WorkflowNode): void;
}>();

const isDragging = ref(false);

const nodeWidth=ref<number>(200);


// 获取参数颜色
const getParamColor = (type: string,fieldType:string) => {
	if('reference' === type || 'exec' === type){
		return "#ffffff";
	}else{
		if('string' === fieldType) return "#FC00D2";
		else if('bool' === fieldType) return "#930000";
		else if('float' === fieldType) return "#38D500";
		else if('int' === fieldType) return "#1FE3AF";
		else if('double' === fieldType) return "#aaff00";
		else if('objct' === fieldType) return "#01A4EC";
		else if('HTTP_DS' === fieldType) return "#5555ff";
		else if('MQTT' === fieldType) return "#ffaa00";
		else if('datasources' === fieldType) return "#0055ff";
		else if('JSONObject' === fieldType) return "#00aaff";
		else if('JSONArray' === fieldType) return "#00aaff";
		else if('any' === fieldType) return "#666";
		else return "#0055ff";
	}
};

const getNodeHeight = () => {
	const height=props.node.data.inputs.length>props.node.data.outputs.length? props.node.data.inputs.length*30 :props.node.data.outputs.length*30
	if(props.node.showHead=='1'){
		return height +34;
	}else{
		return height ;
	}
  
};

// 鼠标按下时检查到的PortId
const curPortId=ref<string>("");
const curPortColor=ref<string>("");

// 存储鼠标在节点头部的相对位置
const dragOffset = reactive({ x: 0, y: 0 });

const handleClick = () => {
  emit('select', props.node.id);
};

// 提取 SVG 变换相关的工具函数
const getSvgTransform = (svg: SVGSVGElement) => {
  const contentGroup = svg.querySelector('.content-group');
  const scaleGroup = contentGroup?.querySelector('g');
  const transform = contentGroup?.getAttribute('transform') || '';
  const scaleTransform = scaleGroup?.getAttribute('transform') || '';
  
  const translateMatch = transform.match(/translate\(([-\d.]+),([-\d.]+)\)/);
  const scaleMatch = scaleTransform.match(/scale\(([\d.]+)\)/);
  
  return {
    scale: scaleMatch ? parseFloat(scaleMatch[1]) : 1,
    translateX: translateMatch ? parseFloat(translateMatch[1]) : 0,
    translateY: translateMatch ? parseFloat(translateMatch[2]) : 0
  };
};

let svgRect: DOMRect;
let scale: number; let translateX: number; let translateY: number;

// 1. 添加缓存相关变量
const connections: Connection[] = [];
const portPositionsCache = new Map<string, { sourcePos: Position, targetPos: Position }>();
let initialX = 0;
let initialY = 0;

// 1. 添加节流函数
const throttle = (fn: Function, delay: number) => {
  let lastTime = 0;
  return (...args: any[]) => {
    const now = Date.now();
    if (now - lastTime >= delay) {
      fn.apply(null, args);
      lastTime = now;
    }
  };
};

/**
 * 按住节点头部开始拖拽
 */
const handleDragStart = (e: MouseEvent) => {
  if (e.button !== 0) return;
  if (curPortId.value) return;
  
  e.preventDefault();
  e.stopPropagation();
  
  handleClick();
  
  if(!props.svgContainer) return;
  
  const svg = props.svgContainer;
  if (!svg) return;
  const _data = getSvgTransform(svg);
  
  scale = _data.scale;
  translateX = _data.translateX;
  translateY = _data.translateY;
  
  svgRect = svg.getBoundingClientRect();
  
  // 记录初始位置
  initialX = props.node.position.x;
  initialY = props.node.position.y;
  
  // 获取相关连接并缓存端口位置
  connections.length = 0; // 清空数组
  portPositionsCache.clear(); // 清空缓存
  
  workflowStore.state.connections.forEach(conn => {
    if (conn.sourcePortId.includes(props.node.id) || 
        conn.targetPortId.includes(props.node.id)) {
		connections.push(conn);
      // 缓存源端口和目标端口位置
      const sourcePos = getPortPosition(conn.sourcePortId);
      const targetPos = getPortPosition(conn.targetPortId);
      
      if (sourcePos && targetPos) {
        portPositionsCache.set(conn.id, {
          sourcePos,
          targetPos
        });
      }
    }
  });
  
  if(props.node.showHead=='1'){
    const nodeHead = document.getElementById(`${props.node.id}_head`);
    if (!nodeHead) return;
    const headRect = nodeHead.getBoundingClientRect();
    dragOffset.x = (e.clientX - headRect.left) / scale;
    dragOffset.y = (e.clientY - headRect.top) / scale;
  } else {
    const nodeBody = document.getElementById(`${props.node.id}_body`);
    if (!nodeBody) return;
    const bodyRect = nodeBody.getBoundingClientRect();
    dragOffset.x = (e.clientX - bodyRect.left + 4) / scale;
    dragOffset.y = (e.clientY - bodyRect.top + 8) / scale;
  }
  
  isDragging.value = true;
  window.addEventListener('mousemove', handleMouseMove);
  window.addEventListener('mouseup', handleMouseUp);
};

const convertToSVGCoordinates = (e: MouseEvent): any => {
  // 计算相对于 SVG 的坐标
  const x = (e.clientX - svgRect.left - translateX) / scale - dragOffset.x;
  const y = (e.clientY - svgRect.top - translateY) / scale - dragOffset.y;
  return {
    x,
    y
  };
};

// 2. 优化连接线更新逻辑
const updateNodeConnections = throttle(() => {
  if (connections.length === 0) return;
  
  // 计算一次位移，避免重复计算
  const dx = props.node.position.x - initialX;
  const dy = props.node.position.y - initialY;
  
  // 批量构建路径
  const updates = connections.map(conn => {
    const cached = portPositionsCache.get(conn.id);
    if (!cached) return null;
    
    const { sourcePos, targetPos } = cached;
    
    // 根据节点移动调整位置
    const adjustedSourcePos = conn.sourcePortId.includes(props.node.id) 
      ? { x: sourcePos.x + dx, y: sourcePos.y + dy }
      : sourcePos;
      
    const adjustedTargetPos = conn.targetPortId.includes(props.node.id)
      ? { x: targetPos.x + dx, y: targetPos.y + dy }
      : targetPos;
    
    // 计算新路径
    const dist = Math.abs(adjustedTargetPos.x - adjustedSourcePos.x) / 2;
    const path = `M${adjustedSourcePos.x} ${adjustedSourcePos.y} C${adjustedSourcePos.x + dist} ${adjustedSourcePos.y} ${adjustedTargetPos.x - dist} ${adjustedTargetPos.y} ${adjustedTargetPos.x} ${adjustedTargetPos.y}`;
    
    return {
      ...conn,
      path
    };
  }).filter(Boolean) as Connection[];
  
  if (updates.length > 0) {
    // 使用 requestAnimationFrame 进行批量更新
    requestAnimationFrame(() => {
      workflowStore.batchUpdateConnections(updates);
    });
  }
}, 16); // 约60fps

// 3. 修改 handleMouseMove 方法
const handleMouseMove = (e: MouseEvent) => {
  if (!isDragging.value) return;
  
  const position = convertToSVGCoordinates(e);
  if(position != undefined) {
    props.node.position.x = position.x;
    props.node.position.y = position.y;
    
    // 使用节流后的更新函数
    updateNodeConnections();
  }
};

// 4. 修改 handleMouseUp 方法
const handleMouseUp = () => {
  if (!isDragging.value) return;
  
  isDragging.value = false;
  
  // 最后一次更新连接线
  const dx = props.node.position.x - initialX;
  const dy = props.node.position.y - initialY;
  
  const finalUpdates = connections.map(conn => {
    const cached = portPositionsCache.get(conn.id);
    if (!cached) return null;
    
    const { sourcePos, targetPos } = cached;
    const adjustedSourcePos = conn.sourcePortId.includes(props.node.id) 
      ? { x: sourcePos.x + dx, y: sourcePos.y + dy }
      : sourcePos;
      
    const adjustedTargetPos = conn.targetPortId.includes(props.node.id)
      ? { x: targetPos.x + dx, y: targetPos.y + dy }
      : targetPos;
    
    const dist = Math.abs(adjustedTargetPos.x - adjustedSourcePos.x) / 2;
    const path = `M${adjustedSourcePos.x} ${adjustedSourcePos.y} C${adjustedSourcePos.x + dist} ${adjustedSourcePos.y} ${adjustedTargetPos.x - dist} ${adjustedTargetPos.y} ${adjustedTargetPos.x} ${adjustedTargetPos.y}`;
    
    return {
      ...conn,
      path
    };
  }).filter(Boolean) as Connection[];
  
  if (finalUpdates.length > 0) {
    workflowStore.batchUpdateConnections(finalUpdates);
  }
  
  workflowStore.updateContainments();
  
  // 清理缓存
  connections.length = 0;
  portPositionsCache.clear();
  
  window.removeEventListener('mousemove', handleMouseMove);
  window.removeEventListener('mouseup', handleMouseUp);
};

// 检查两个端口是否可以连接
const canPortsConnect = (sourcePortId: string, targetPortId: string) => {
  // 检查是否已存在连接
  const existingConnection = workflowStore.state.connections.find(conn => 
    (conn.sourcePortId === sourcePortId && conn.targetPortId === targetPortId) ||
    (conn.sourcePortId === targetPortId && conn.targetPortId === sourcePortId)
  );

  if (existingConnection) {
    console.warn('Connection already exists between these ports');
    return false;
  }
  
  // 获取源端口和目标端口的节点和端口信息
  const sourceNode = workflowStore.state.nodes.find(node => {
    if(node.data.outputs){
      return node.data.outputs.some(out => `output-${node.id}-${out.id}-port` === sourcePortId)
    }else{
      return null; 
    }
  });
  
  const targetNode = workflowStore.state.nodes.find(node => {
    if(node.data.inputs){
      return node.data.inputs.some(input => `input-${node.id}-${input.id}-port` === targetPortId);
    }else{
      return null;
    }
  });
  
  if (!sourceNode || !targetNode) return false;
  
  if(sourceNode.id===targetNode.id) return false;
  
  const sourceNodeType = sourceNode.data.outputs.find(node => {
    if(`output-${sourceNode.id}-${node.id}-port` === sourcePortId){
      return node
    }
  });
  
  const targetNodeType = targetNode.data.inputs.find(node => {
    if(`input-${targetNode.id}-${node.id}-port` === targetPortId){
      return node
    }
  });
  
  if (!sourceNodeType || !targetNodeType) return false;
  
  if(sourceNodeType.type !=targetNodeType.type) return false;

  // 获取具体的端口
  const sourcePort = sourceNode.data.outputs.find(out => 
    `output-${sourceNode.id}-${out.id}-port` === sourcePortId
  );
  const targetPort = targetNode.data.inputs.find(input => 
    `input-${targetNode.id}-${input.id}-port` === targetPortId
  );
  
  if (!sourcePort || !targetPort) return false;
  
  if(sourcePort?.type==='exec'){
	  const execExistingConnection = workflowStore.state.connections.find(conn =>{
		  return  (conn.sourcePortId === sourcePortId);
		}
	  );
	  if(execExistingConnection){
		   workflowStore.removeConnectionsByPortId(sourcePortId);
	  }
	  return sourcePort.type===targetPort?.type;
  }
  
  if(sourcePort.type===targetPort.type){
	  return sourcePort.fieldType===targetPort.fieldType
  }
  // 检查端口类型是否匹配 sourcePort.type === targetPort.type
  return false;
};

/**
 * 端口拖拽
 */
const handleDragPortStart = (portId:string,e: MouseEvent) => {
 
  // 端口拖拽
  if (e.button === 0) {
	  e.preventDefault();
	  e.stopPropagation();
    if((e.target instanceof Element) && e.target!=null && e.target.getAttribute("portId")!=""){
      curPortId.value= portId || e.target.getAttribute("portId")+"";
      if(curPortId.value==null || curPortId.value=="" || curPortId.value=="null"){
        return;
      }
      
      const sourceNodeType = props.node.data.outputs.find(node => {
        if(`output-${props.node.id}-${node.id}-port` === curPortId.value){
          return node
        }
      });
      
      if(!sourceNodeType){
        return;
      }
      curPortColor.value= getParamColor(sourceNodeType?.type,sourceNodeType?.fieldType);
      window.addEventListener('mousemove', handleDragPortMouseMove);
      window.addEventListener('mouseup', handleDragPortMouseUp);
    }
  }
};

const activePath = ref<SVGPathElement | null>(null);

/**
 * 创建动态连接线
 */
const createDynamicPath = () => {
  // 删除已存在的临时路径
  activePath.value?.remove();
  
  // 创建新的路径元素
  const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  path.setAttribute('stroke', curPortColor.value);
  path.setAttribute('fill', 'none');
  path.setAttribute('stroke-width', '2');
  path.setAttribute('class', 'dynamic-connection');
  
  // 获取连接线容器
  const linksContainer = document.querySelector('#linksContainer');
  if (linksContainer) {
    linksContainer.appendChild(path);
    activePath.value = path;
  }
  
  return path;
};

/**
 * 更新连接线路径
 */
const updateConnectionPath = (sourcePos: Position, targetPos: Position) => {
  if (!activePath.value) {
    activePath.value = createDynamicPath();
  }
  
  const dist = Math.abs(targetPos.x - sourcePos.x) / 2;
  activePath.value?.setAttribute('d', 
    `M${sourcePos.x} ${sourcePos.y} C${sourcePos.x + dist} ${sourcePos.y} ${targetPos.x - dist} ${targetPos.y} ${targetPos.x} ${targetPos.y}`
  );
};

/**
 * 鼠标拖动Port移动
 */
const handleDragPortMouseMove = (e: MouseEvent) => {
  if (curPortId.value === "") return;
  const svg = (e.target as Element).closest('svg') as SVGSVGElement;
  if (!svg) return;

  const svgRect = svg.getBoundingClientRect();
  const { scale, translateX, translateY } = getSvgTransform(svg);

  // 获取源端口位置
  const sourcePos = getPortPosition(curPortId.value);
  if (!sourcePos) return;

  // 计算当前鼠标位置
  const currentX = (e.clientX - svgRect.left - translateX) / scale;
  const currentY = (e.clientY - svgRect.top - translateY) / scale;
  
  // 重置所有端口的高亮状态
  const allPorts = document.querySelectorAll('[portId]');
  allPorts.forEach(port => {
    if (port instanceof Element) {
      port.classList.remove('port-hover');
      const bg = port.closest('.port-background');
      if (bg) {
        bg.setAttribute('opacity', '0');
      }
    }
  });

  // 检测鼠标是否在其他端口上方
  const targetPort = document.elementFromPoint(e.clientX, e.clientY);
  if (targetPort instanceof Element) {
    const portId = targetPort.getAttribute('portId');
    if (portId && portId !== curPortId.value) {
      // 高亮目标端口
      targetPort.classList.add('port-hover');
      const bg = targetPort.closest('.port-background');
      if (bg) {
        bg.setAttribute('opacity', '1');
      }
      // 使用目标端口的位置绘制连接线
      const targetPos = getPortPosition(portId as string);
      if (targetPos) {
        updateConnectionPath(sourcePos, targetPos);
        return;
      }
    }
  }
  // 如果没有目标端口，使用鼠标位置绘制连接线
  updateConnectionPath(sourcePos, { x: currentX, y: currentY });
};

/**
 * 鼠标拖拽Port释放
 */
const handleDragPortMouseUp = (e: MouseEvent) => {
  if (curPortId.value === "") return;

  // 检测释放时是否在目标端口上
  const targetPort = document.elementFromPoint(e.clientX, e.clientY);
  if (targetPort instanceof Element) {
    const targetPortId = targetPort.getAttribute('portId');
    if (targetPortId && targetPortId !== curPortId.value) {
      // 创建连接，使用类型断言确保 targetPortId 是 string 类型
	  if(canPortsConnect(curPortId.value,targetPortId as string)){
		  createConnection(curPortId.value, targetPortId as string);
		  return;
	  }
    }
  }

  // 清理状态
  curPortId.value = "";
  curPortColor.value = "";
  activePath.value?.remove();
  activePath.value = null;
  window.removeEventListener('mousemove', handleDragPortMouseMove);
  window.removeEventListener('mouseup', handleDragPortMouseUp);
};

/**
 * 创建连接
 */
const createConnection = (sourcePortId: string, targetPortId: string) => {
  // 获取源端口和目标端口的元素
  const sourcePort = document.querySelector(`[id="${sourcePortId}-sign"]`);
  const targetPort = document.querySelector(`[id="${targetPortId}-sign"]`);
  
  if (!sourcePort) {
    console.warn('Source port not found:', sourcePortId);
    return;
  }
  if (!targetPort) {
    console.warn('Target port not found:', targetPortId);
    return;
  }
  
  // 获取输入端口的类型
  const inputPort = props.node.data.inputs.find(input => 
    `input-${props.node.id}-${input.id}-port` === sourcePortId
  );
  
  // 只有在输入端口类型为 exec 时才移除现有连接
  if (inputPort?.type === 'exec') {
    workflowStore.removeConnectionsByPortId(sourcePortId);
  }
  
  // 更新端口样式为实心
  sourcePort.setAttribute('fill', '#fff');
  sourcePort.setAttribute('style', 'fill: #fff !important');
  targetPort.setAttribute('fill', '#fff');
  targetPort.setAttribute('style', 'fill: #fff !important');
  
  // 获取连接路径
  const path = getConnectionPath(sourcePortId, targetPortId);

  // 创建永久连接线
  const connection = {
	id: `${uuidv4()}`,
    sourcePortId,
    targetPortId,
    path,
    connected: true,
    color: curPortColor.value
  };

  // 保存到 store
  workflowStore.addConnection(connection);
};

// 优化端口位置计算
const getPortPosition = (portId: string) => {
	
  const port = document.querySelector(`[id="${portId}-sign"]`);
  
  const svg = props.svgContainer;
  if (!svg) return;
 
  if (!port || !props.svgContainer) return null;
  const svgRect = props.svgContainer.getBoundingClientRect();
  const portRect = port.getBoundingClientRect();
  const { scale, translateX, translateY } = getSvgTransform(props.svgContainer);

  const x = (portRect.left - svgRect.left - translateX) / scale + portRect.width / 2 / scale;
  const y = (portRect.top - svgRect.top - translateY) / scale + portRect.height / 2 / scale;

  return { x, y };
};

/**
 * 获取连接线的路径信息
 * @param sourcePortId 源端口ID
 * @param targetPortId 目标端口ID
 * @returns 贝塞尔曲线路径
 */
const getConnectionPath = (sourcePortId: string, targetPortId: string) => {
  const sourcePos = getPortPosition(sourcePortId);
  const targetPos = getPortPosition(targetPortId);
  
  if (!sourcePos || !targetPos){
	    return '';
  }
  
  // 计算控制点的水平偏移量
  const dist = Math.abs(targetPos.x - sourcePos.x) / 2;
  
  // 生成贝塞尔曲线路径
  return `M${sourcePos.x} ${sourcePos.y} C${sourcePos.x + dist} ${sourcePos.y} ${targetPos.x - dist} ${targetPos.y} ${targetPos.x} ${targetPos.y}`;
};

// 在 script setup 中添加
const isPortConnected = (portId: string) => {
  return workflowStore.state.connections.some(conn => 
    conn.sourcePortId === portId || conn.targetPortId === portId
  );
};

// 优化文本宽度计算
const getTextWidth = (text: string) => {
  if (!text) return 0;
  const canvas = document.createElement('canvas');
  const context = canvas.getContext('2d');
  if (!context) return 0;
  context.font = '10px Arial'; // 设置字体样式
  return context.measureText(text).width; // 返回文本宽度
};

// 计算端口背景宽度
const getPortBackgroundWidth = (fieldName: string) => {
  // 文本宽度 + 左边距(25) + 右边距(10) + 端口圆圈宽度(20)
  const textWidth = getTextWidth(fieldName);
  return textWidth==0?25:(23+textWidth+8);
};

// 计算最大端口背景宽度
const getMaxPortBackgroundWidth = () => {
  let inputMaxWidth = 0;

  // 计算输入端口的最大宽度
  props.node.data.inputs.forEach(input => {
    const width = getPortBackgroundWidth(input.click === '1' ? (input.value ? (input.name + '(' + input.value + ')') : input.name) : input.name);
    if (width > inputMaxWidth) {
      inputMaxWidth = width;
    }
  });

 let outputMaxWidth = 0;
  // 计算输出端口的最大宽度
  props.node.data.outputs.forEach(output => {
    const width = getPortBackgroundWidth(output.click === '1' ? (output.value ? (output.name + '(' + output.value + ')') : output.name) : output.name);
    if (width > outputMaxWidth) {
      outputMaxWidth = width;
    }
  });
  const width = getPortBackgroundWidth( props.node.title);
  
  if(width>(outputMaxWidth + inputMaxWidth)){
	   nodeWidth.value=width +40;
  }else{
	   nodeWidth.value=outputMaxWidth + inputMaxWidth +40;
  }
  props.node.size.width= nodeWidth.value;
  return nodeWidth;
};

watch(() => props.node.size.width, (newWidth) => {
	if (newWidth && !isFirst.value) {
		const affectedConnections = ref<Connection[]>([]);
		affectedConnections.value = workflowStore.state.connections.filter((conn: { sourcePortId: string; targetPortId: string; }) => {
			const sourceMatch = conn.sourcePortId.match(/(?:input|output)-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
			const targetMatch = conn.targetPortId.match(/(?:input|output)-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
			const sourceNodeId = sourceMatch ? sourceMatch[1] : '';
			const targetNodeId = targetMatch ? targetMatch[1] : '';
			return props.node.id === sourceNodeId || props.node.id === targetNodeId;
		});
		
		if(affectedConnections.value.length>0){
			workflowStore.updatedNodeConnections(affectedConnections.value,props.svgContainer);
		}
	}
}, { deep: true });


// 添加一个计算属性来控制节点头部的样式
const headCursor = computed(() => {
  return curPortId.value ? 'default' : 'move';
});

// 修改右键菜单处理函数
const handleContextMenu = (portId: string, event: MouseEvent, _output: any) => {
	if('1'==_output.click){
		emit('port:menu:show', portId, props.node,_output,event);
	}
};

/**
 * 添加引用脚
 */
const addReference = () => {
  emit('port:menu:hide');
  const outputs = props.node.data.outputs;
  const newOutput = {
    code: "exec",
    id: uuidv4(),
    name: "Then",
    type: "exec",
    value: "",
	click:"1",
	fieldType:'any'
  };
  const lastNonRefIndex = outputs.length - 1;
  outputs.splice(lastNonRefIndex, 0, newOutput);
  workflowStore.incrementVersion();
};

// 组件卸载时清理
onUnmounted(() => {
});

// 导出函数供外部使用
defineExpose({
  getPortPosition,
  getConnectionPath
});

// 组件挂载后计算尺寸
onMounted(() => {
	getMaxPortBackgroundWidth();
	isFirst.value=false;
});

</script>

<style lang="scss" scoped>
.workflow-node {
  cursor: pointer;
  pointer-events: all;
  transform-box: fill-box;
  shape-rendering: geometricPrecision;

  .node-head {
    cursor: grab;
    pointer-events: all;
    user-select: none;
    
    &:active {
      cursor: grabbing;
    }
    
    text {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    }
  }

  .node-background {
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 1));
  }

  &.selected {
    rect.node-background {
      stroke: #409EFF;
      stroke-width: 2;
    }
  }

  .port {
    transition: fill 0.2s;
    
    &:hover {
      fill: #409eff;
    }
  }
  
  .node-icon {
    color: #fff;
    transform-origin: center;
    will-change: transform;
	pointer-events: none;
  }
  
  .node-type-indicator {
    border-radius: 16px;
  }

  .param-item {
    &:hover {
      opacity: 0.8;
    }
  }

  .node-content-row {
    .port-group {
      .port-background {
        // transition: all 0.2s ease;
        opacity: 0;
        
        &.port-hover {
          opacity: 0.1;
          stroke: #409eff;
          stroke-width: 2px;
        }
      }
      
      &:hover {
        .port-background {
          opacity: 1;
        }
      }
    }
  }

  .port-hover {
    .node-input,
    .node-out {
      stroke: #409eff;
      stroke-width: 2px;
    }
    
    circle {
      stroke: #409eff;
      stroke-width: 2px;
    }
  }

  .port-dropdown {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    color: #fff;
    opacity: 0;
    cursor: pointer;
    transition: opacity 0.2s;
    
    &:hover {
      opacity: 1;
    }
    
    .el-icon {
      font-size: 12px;
    }
  }
  
  .node-inputs-content-row:hover {
    .port-dropdown {
      opacity: 0.7;
    }
  }
}

:deep(.el-select) {
  .el-input__wrapper {
    background-color: rgba(0, 0, 0, 0.3);
    box-shadow: none;
    border: 1px solid rgba(255, 255, 255, 0.1);
    cursor: pointer;
  }
  
  .el-input__inner {
    color: #fff;
    
    &::placeholder {
      color: rgba(255, 255, 255, 0.5);
    }
  }
  
  .el-select__caret {
    color: #fff;
  }
}

/* 确保下拉菜单在最上层 */
:global(.node-select-dropdown) {
  z-index: 9999 !important;
  
  .el-select-dropdown__wrap {
    max-height: 300px;
  }

  .el-select-dropdown__item {
    color: #fff;
    
    &.hover, &:hover {
      background-color: rgba(64, 158, 255, 0.1);
    }
    
    &.selected {
      background-color: rgba(64, 158, 255, 0.2);
      color: #409eff;
    }
  }

  .el-scrollbar__view {
    background-color: #1a1a1a;
  }

  .el-select-dropdown__list {
    padding: 4px 0;
  }

  .el-popper__arrow {
    display: none;
  }
}

.node-body{
	background-color: red;
}

/* 修复下拉菜单在 SVG 中的定位问题 */
:global(.el-popper) {
  position: fixed !important;
}

.menu-container {
  pointer-events: all;
}

.context-menu {
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
  
  .menu-item {
    padding: 8px 16px;
    color: #fff;
    cursor: pointer;
    transition: all 0.2s;
    white-space: nowrap;
    font-size: 12px;
    line-height: 1.5;
    
    &:hover {
      background: rgba(64, 158, 255, 0.1);
      color: #409EFF;
    }
    
    &.disabled {
      color: #666;
      cursor: not-allowed;
      
      &:hover {
        background: none;
        color: #666;
      }
    }
  }
}

.port-label-group {
  .port-label {
    cursor: pointer;
    user-select: none;
    
    // &:hover {
    //   fill: #409EFF;
    // }
  }
  
  :deep(foreignObject) {
    overflow: visible;
    pointer-events: all;
  }
}

:deep(.el-dropdown-menu) {
  background: #1e1e1e;
  border: 1px solid #333;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
  
  .el-dropdown-menu__item {
    color: #fff;
    padding: 8px 16px;
    
    &:not(.is-disabled):hover {
      background-color: rgba(64, 158, 255, 0.1);
      color: #409EFF;
    }
    
    &.is-disabled {
      color: #666;
      cursor: not-allowed;
    }
  }
}

.menu-item {
  padding: 8px 16px;
  color: #fff;
  cursor: pointer;
  transition: all 0.2s;
  font-size: 12px;
  line-height: 1.5;
  white-space: nowrap;
  
  &:hover {
    background: rgba(64, 158, 255, 0.1);
    color: #409EFF;
  }
  
  &.disabled {
    color: #666;
    cursor: not-allowed;
    
    &:hover {
      background: none;
      color: #666;
    }
  }
}

.port-input {
  cursor: pointer;
  
  rect {
    transition: all 0.2s;
    
    &:hover {
      stroke: #409EFF;
    }
  }
  
  text {
    pointer-events: none;
    user-select: none;
  }
}
</style> 